#include <stdio.h>
#include <stdlib.h>
#include "wallinit.h"

void nameProtocol(void)
{
    sprintf(protocol[0], "UNKNOWN");
    sprintf(protocol[1], "TCP");
    sprintf(protocol[2], "UDP");
    sprintf(protocol[3], "ICMP");
    sprintf(protocol[4], "RIP");
}

void nameNetCard(void)
{
    sprintf(netcard[0], "LO0");
    sprintf(netcard[1], "ETH0");
    sprintf(netcard[2], "ETH1");
    sprintf(netcard[3], "ETH2");
    sprintf(netcard[4], "ETH16");
}

bool inexistConfig(char* filename)
{
    bool ret = false;
    FILE * fp = fopen(filename, "r");
    if (fp)
        fclose(fp);
    else
        ret = true;

    return ret;
}

bool createCfg(void)
{
    bool ret = false;
    FILE * fp = fopen(cfgname, "w");
    if (fp)
    {
        fprintf(fp, "%*s%s%*s\n", (LEN_CFG_LINE - 22) / 2, " ", "*** DO NOT MODIFY ***", LEN_CFG_LINE - (LEN_CFG_LINE - 22) / 2 - 22, " ");
        fprintf(fp, "%-19s  %-15s  %-5s  %-24s\n", \
            "Hash", "IP address", "Type", "Written time");
        fclose(fp);
        printf("Created Config File Succeeded!\n");
        ret = true;
    }
    else
        printf("Created Config File Failed!\n");

    return ret;
}

bool createPortCfg(void)
{
    bool ret = false;
    FILE * fp = fopen(portcfgname, "w");
    if (fp)
    {
        fprintf(fp, "%*s%s%*s\n", (LEN_PORT_LINE - 22) / 2, " ", "*** DO NOT MODIFY ***", LEN_PORT_LINE - (LEN_PORT_LINE - 22) / 2 - 22, " ");
        fprintf(fp, "%-15s  %-5s  %-7s  %-24s\n", \
            "Hash", "Port", "Type", "Written time");
        fclose(fp);
        printf("Created Port Config File Succeeded!\n");
        ret = true;
    }
    else
        printf("Create Port Config File Failed!\n");

    return ret;
}

bool createProtocolCfg(void)
{
    bool ret = false;
    FILE * fp = fopen(protocolcfgname, "w");
    if (fp)
    {
        fprintf(fp, "%*s%s%*s\n", (LEN_PROTOCOL_LINE - 22) / 2, " ", "*** DO NOT MODIFY ***", LEN_PROTOCOL_LINE - (LEN_PROTOCOL_LINE - 22) / 2 - 22, " ");
        fprintf(fp, "%2s %-7s  %-22s\n", "No", "Proto", "Status");
        for (int i = 0; i < NUM_PROTOCOL; i++)
            fprintf(fp, "%2d %-7s  %-22s\n", i + 1, protocol[i], "SRC : PASS  DST : PASS");

        fclose(fp);
        printf("Created Protocol Config File Succeeded!\n");
        ret = true;
    }
    else
        printf("Create Protocol Config File Failed!\n");

    return ret;
}

bool createNetCardCfg(void)
{
    bool ret = false;
    FILE * fp = fopen(netcardcfgname, "w");
    if (fp)
    {
        fprintf(fp, "%*s%s%*s\n", (LEN_NETCARD_LINE - 22) / 2, " ", "*** DO NOT MODIFY ***", LEN_NETCARD_LINE - (LEN_NETCARD_LINE - 22) / 2 - 22, " ");
        fprintf(fp, "%2s %-6s  %-22s\n", "No", "NC", "Status");
        for (int i = 0; i < NUM_NETCARD; i++)
            fprintf(fp, "%2d %-6s  %-22s\n", i + 1, netcard[i], "SRC : PASS  DST : PASS");

        fclose(fp);
        printf("Created Net Card Config File Succeeded!\n");
        ret = true;
    }
    else
        printf("Create Net Card Config File Failed!\n");

    return ret;
}

static inline bool getTotalLines(int type)
{
    bool ret = false;

    char* filename;
    int LEN;
    int* totalLines;
    if (type)
    {
        filename = cfgname;
        LEN = LEN_CFG_LINE;
        totalLines = &totalIPLines;
        printf("Reading IP Items...\n");
    }
    else
    {
        filename = portcfgname;
        LEN = LEN_PORT_LINE;
        totalLines = &totalPtLines;
        printf("Reading Port Items...\n");
    }

    FILE * fp = fopen(filename, "r");
    if (fp)
    {
        fseek(fp, 0, SEEK_END);
        *totalLines = ftell(fp) / LEN - 2;
        fclose(fp);
        printf("Total Items: %d\n", *totalLines);
        ret = true;
    }
    else
        printf("Get Total Items Failed!\n");

    return ret;
}

bool initwall(void)
{
    bool ret = false;

    printf("Initializing...\n");

    FILE * fp = fopen(".wallinit", "r");
    if (fp)
    {
        char* filepath = (char*)malloc((MAX_FILE_PATH_LEN + 1) * sizeof(char));

        fseek(fp, 25 * sizeof(char), SEEK_SET);
        char c;
        for (int i = 0; i < (MAX_FILE_PATH_LEN + 1); i++)
        {
            c = fgetc(fp);
            if (c != '\n')
                *(filepath + i) = c;
            else
            {
                *(filepath + i) = '\0';
                break;
            }
        }
        // Windows only
        sprintf(cfgname, "%s\\firewall\\.wallcfg", filepath);
        sprintf(portcfgname, "%s\\firewall\\.ptcfg", filepath);
        sprintf(protocolcfgname, "%s\\firewall\\.protcfg", filepath);
        sprintf(netcardcfgname, "%s\\firewall\\.ncdcfg", filepath);
        sprintf(tmpname, "%s\\firewall\\.tmp", filepath);
        printf("Config File Path: %s\n", filepath);

        // 因为没有找到合适的方法，只好自己命名 XD
        nameProtocol();
        nameNetCard();

        // 如果不存在则创建文件
        if (inexistConfig(cfgname))
        {
            char* command = (char*)malloc((MAX_FILE_PATH_LEN + 17) * sizeof(char));
            // Windows only
            sprintf(command, "mkdir %s\\firewall", filepath);
            system(command);
            free(command);
            createCfg();
        }

        if (inexistConfig(portcfgname))
            createPortCfg();
        
        if (inexistConfig(protocolcfgname))
            createProtocolCfg();

        if (inexistConfig(netcardcfgname))
            createNetCardCfg();

        free(filepath);

        int years, months, days;
        char* buff = (char*)malloc(8 * sizeof(char));
        fseek(fp, 10 * sizeof(char), SEEK_CUR);
        fscanf(fp, "%d", &years);
        fgets(buff, 7, fp);
        fscanf(fp, "%d", &months);
        fgets(buff, 8, fp);
        fscanf(fp, "%d", &days);
        printf("Config TTL: %4d years, %4d months, %4d days\n",\
         years, months, days);
        TTL = (years * 365 + months * 30 + days) * 24 * 3600;

        free(buff);

        fclose(fp);

        getTotalLines(1);
        getTotalLines(0);

        printf("Init Succeeded!\n\n");
        ret = true;
    }
    else
    {
        FILE * fp = fopen(".wallinit", "w");
        if (fp)
        {
            char* filepath = (char*)malloc((MAX_FILE_PATH_LEN + 1)\
             * sizeof(char));
            printf("Please input filepath for storing config file");
            printf("(default the same as this file):\n");
            printf("eg: /usr/bin/ or D:\\desktop\\firewall\n");
            scanf("%s", filepath);
            sprintf(cfgname, "%s/.wallconfig", filepath);
            free(filepath);

            u32 years, months, days;
            printf("\nPlease input TTL of config with the following format:\n");
            printf("${years(=365 days)} ${months(=30 days)} ${days}\n");
            printf("eg: 0 6 0 (or input nothing for 3 months)\n");
            scanf("%d %d %d", &years, &months, &days);
            TTL = (years * 365 + months * 30 + days) * 24 * 3600;

            fprintf(fp, "%s\n", "Firewall init");
            fprintf(fp, "Filepath: ");
            fprintf(fp, "%s\n", filepath);
            fprintf(fp, "     TTL: ");
            fprintf(fp, "%4d years %4d months %4d days\n", years, months, days);
            fclose(fp);

            createCfg();

            ret = true;
            totalIPLines = 0;
            totalPtLines = 0;
        }
        else
            printf("Create Init File Failed!\n");
    }

    return ret;
}